package com.mezz.bones.im.logic.process.interfaces;


import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.mezz.bones.framework.base.util.ExecutionTimeLoggerUtil;
import com.mezz.bones.im.common.enums.ActionCodeEnum;
import com.mezz.bones.im.common.event.MessageSendWithConnectEvent;
import com.mezz.bones.im.common.exception.ImBaseException;
import com.mezz.bones.im.common.message.base.MessageHeader;
import com.mezz.bones.im.common.domain.user.ImUserConnectInfo;
import com.mezz.bones.im.common.process.IMessageProcessor;
import com.mezz.bones.im.common.result.ImResultCode;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 业务逻辑层处理通用模板
 *
 * @param <Req>
 */
@Service
public abstract class AbstractMessageLogicProcess<Req, Res> implements MessageLogicProcess<Req, Res> {

    @Resource
    private Validator validator;

    @Resource
    private IMessageProcessor messagePublisher;

    public static final String MESSAGE_BIZ_CONTEXT_KEY = "ctx";

    @Resource(name = "imBizMessageActionExecutor")
    private ThreadPoolTaskExecutor imBizMessageActionExecutor;

    public Res handler(ImUserConnectInfo senderUserConnectInfo, MessageHeader header, Object req) {

        //编排消息处理流程模板 - 稳定业务(消息校验-消息存储-消息ACK响应-消息基础逻辑处理(单聊消息-发送/删除/聊天记录...))

        log.debug("----------- ServiceMessageProcessor handler start:[{}]: header: [{}] : req: [{}]", this.tag(), JSONObject.toJSONString(header), JSONObject.toJSONString(req));
        Req packData = null;
        try {
            packData = convert2T(req);
        } catch (Exception e) {
            throw new ImBaseException(ImResultCode.SYS_ERROR, "消息请求body格式化异常");
        }

        Req request = packData;
        AtomicReference<Res> resAtomicReference = new AtomicReference<>();

        ActionCodeEnum actionCodeEnum = ActionCodeEnum.findEnum(this.tag());

        ExecutionTimeLoggerUtil.logExecutionTime(actionCodeEnum.getText(), () -> {

            //上下文对象
            Map<String, Object> ctxMap = new HashMap<>();

            //前置处理参数
            preHandlerParam(senderUserConnectInfo,header,request);

            //校验请求体参数 用注解方式
            checkParam(request);

            //处理业务逻辑
            resAtomicReference.set(process(senderUserConnectInfo, header, request, ctxMap));

            //ack处理 返回给客户端
            if(header.getAck()){
                ack(senderUserConnectInfo,header,resAtomicReference.get());
            }
            //后置逻辑处理
            imBizMessageActionExecutor.execute(() -> {
                doAfterHandler(senderUserConnectInfo, header, request , resAtomicReference.get(), ctxMap);
            });

        });

        log.debug("----------- ServiceMessageProcessor handler end:[{}]", this.tag());

        return resAtomicReference.get();
    }

    protected void doAfterHandler(ImUserConnectInfo senderUserConnectInfo, MessageHeader header, Req body, Res res, Map<String, Object> ctx) {

    }

    protected void preHandlerParam(ImUserConnectInfo senderUserConnectInfo, MessageHeader header, Req finalBody) {

    }

    @Override
    public void ack(ImUserConnectInfo senderUserConnectInfo, MessageHeader header, Res result) {

        if(senderUserConnectInfo == null || senderUserConnectInfo.getDeviceType().equals("admin")){
            //如果是服务端主动发起调用的 就不用有 ack反馈
            return;
        }

        //消息ACK响应
        messagePublisher.sendMessage2UserConnect(new MessageSendWithConnectEvent(header.getTraceId(), header.getActionCode(), result, senderUserConnectInfo));
    }

    @Override
    public void checkParam(Req req) {
        // 手动验证
        Set<ConstraintViolation<Req>> violations = validator.validate(req);

        if (!violations.isEmpty()) {
            // 获取第一个错误并抛出异常
            ConstraintViolation<Req> violation = violations.iterator().next();
            log.error("Validation error: {}", violation.getMessage());
            throw new ImBaseException(ImResultCode.PARAM_ERROR, "参数验证失败: " + violation.getMessage());
        }
    }

    @Override
    public Req convert2T(Object body) {

        // Get the actual type argument from the generic class
        ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
        Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0]; // Get the generic type (e.g., List<String>)

        // Parse the object to the specific type
        Object res = BeanUtil.toBean(body, ((Class) actualTypeArgument));
        return (Req) res;

    }
}
